/*
* Copyright (c) 2009, Active Web Solutions Limited
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1- Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2- Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3- The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY Active Web Solutions Limited ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Active Web Solutions Limited BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package net.aws.jazure;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import net.aws.jazure.conf.ConfigurationProperties;
import net.aws.jazure.exception.APIRequestFailedException;
import net.aws.jazure.httpconstants.NameSpaces;
import net.aws.jazure.util.ATOMHelper;

import org.jdom.Namespace;
import org.jdom.output.XMLOutputter;
import org.restlet.Client;
import org.restlet.data.ChallengeResponse;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.MediaType;
import org.restlet.data.Method;
import org.restlet.data.Protocol;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.data.Status;
import org.restlet.ext.atom.Content;
import org.restlet.ext.atom.Entry;
import org.restlet.ext.atom.Feed;
import org.restlet.representation.DomRepresentation;
import org.restlet.representation.StringRepresentation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

/**
 * <p>
 * The entry point of the Table Storage API
 * </p>
 * @author dyaa.albakour
 *
 */
public class TableStorage {

	private String accountName;
	private String accountSharedKey;
	private String endPoint;
	
	/**
	 * Create a new TableStorage instance using the account information provided in the
	 * configuration file
	 */
	public TableStorage() {
		super();
		this.accountName = ConfigurationProperties.getInstance().getProperty(ConfigurationProperties.AccountName);
		this.accountSharedKey = ConfigurationProperties.getInstance().getProperty(ConfigurationProperties.AccountSharedKey);;
		this.endPoint = ConfigurationProperties.getInstance().getProperty(ConfigurationProperties.TableStorageEndpoint);
	}
	
	/**
	 * Create a new TableStorage instance with the given storage account and credentials.
	 * 
	 * @param endPoint
	 * @param accountName
	 * @param accountSharedKey
	 */
	public TableStorage(String endPoint, String accountName, String accountSharedKey) {
		this.endPoint = endPoint;
		this.accountName = accountName;
		this.accountSharedKey = accountSharedKey;
	}
	
	
	/**
	 * Get a reference to a newly created <code>Table</code> object.
	 *  This method does not make any calls to the storage service.
	 * 
	 * @param tableName The name of the table
	 * @return A reference to the newly created <code>Table</code> object.
	 */
	public Table getTable(String tableName){  
		return new Table(endPoint,tableName,accountName,accountSharedKey);
		
	}
	
	
	
	
	/**
	 * List the tables in the Table Storage account.
	 * @return A List of the <code>Table</code> objects in the account or null 
	 * 			if the ATOM feed response is not parsed correctly.
	 * @throws APIRequestFailedException If the API request return an unexpected HTTP status code.
	 */
	public List<Table> listTables() 
		throws APIRequestFailedException{
		try{
			Client client = new Client(Protocol.HTTP); 
			ChallengeResponse challengeResponse =  new ChallengeResponse(
		    	ChallengeScheme.HTTP_MS_SHAREDKEY_LITE,
		    	accountName,
		    	accountSharedKey);
			
			String url = endPoint + "/Tables";
			Request request = new Request(Method.GET, url);
		    	    		
			request.setChallengeResponse(challengeResponse);
			Response response = client.handle(request);
					
				
			if(response.getStatus().equals(Status.SUCCESS_OK)){
				
				// parse using the Restlet ATOM feed extension
				Feed feed = new Feed(response.getEntity());
				
				List<Entry> feedEntries = feed.getEntries();
				List<Table> tables = new ArrayList<Table>();
				for(Entry feedEntry:feedEntries){
					
					DomRepresentation domrepresentation =
						new DomRepresentation(feedEntry.getContent().getInlineContent());				
					Node node=  domrepresentation.getNode("/properties/TableName");				
					String tableName = node.getTextContent();
					tables.add(new Table(endPoint,tableName,accountName,accountSharedKey));				
				}
				return tables;
			}else
				throw new APIRequestFailedException(response.getStatus());
		} catch (IOException e) {
			// parsing an ATOM feed failed
			return null;
		}			
	}
	
	/**
	 * create a new table.
	 * @param tableName The name of table. 
	 * @return true if the creation was successful.
	 * @throws APIRequestFailedException If the API request return an unexpected HTTP status code.
	 *
	 */
	public boolean createTable(String tableName) 
		throws APIRequestFailedException{
		
		// TODO validate table name.
		// please see http://msdn.microsoft.com/en-us/library/dd179338.aspx for table name rules.
	    // *  Table names may contain only alphanumeric characters.
	    // * A table name may not begin with a numeric character.
	    // * Table names are case-insensitive.
	    // * Table names must be from 3 through 63 characters long. 
		
		try{
		
			Client client = new Client(Protocol.HTTP); 
			ChallengeResponse challengeResponse =  new ChallengeResponse(
		    	ChallengeScheme.HTTP_MS_SHAREDKEY_LITE,
		    	accountName,
		    	accountSharedKey);
			
			String url = endPoint + "/Tables";
			Request request = new Request(Method.POST, url);
			
			request.setChallengeResponse(challengeResponse);
	
	//		request.setEntity(entry);
	//		DomRepresentation domRepresentation = new DomRepresentation(new MediaType("application/atom+xml"));
	//		domRepresentation.setDocument(ATOMHelper.createATOMFeedDOMDocument(tableName));
	
			String xmlfeed= ATOMHelper.getCreateTableATOMFeed(tableName); 
			StringRepresentation strRepresentation= new  StringRepresentation(
					xmlfeed,new MediaType("application/atom+xml"));
			
	//		request.setEntity(strRepresentation);
			
			request.setEntity(xmlfeed,new MediaType("application/atom+xml"));
			
			Response response = client.handle(request);
			
			Status responseStatus = response.getStatus();
			
			if(responseStatus.equals(Status.SUCCESS_CREATED))
				return true;
			else 
				throw new APIRequestFailedException(responseStatus);
		} catch (IOException e) {
			// create ATOM feed failed
			return false;
		}
		
	}
	
	private void testCreateRestletExtAtomEntry() throws ParserConfigurationException, IOException{
		// create the Atom feed for the request.		
		Feed atomFeed = new Feed();
		
		// The updated property
		atomFeed.setUpdated(new Date());
		
		Entry entry = new Entry();
		entry.setUpdated(new Date());
		
		entry.setNamespaceAware(true);
		entry.putNamespace(NameSpaces.MetaData_Prefix, NameSpaces.MetaData);
		entry.putNamespace(NameSpaces.DataServices_Prefix, NameSpaces.DataServices);
		
		
		//Now the content
		Content content = new Content();
		
		
		// The content should be something like
		//	<m:properties>
		//		<d:TableName>
		//			mytable
		//		</d:TableName>
		//	</m:properties>

		
		Document d = DocumentBuilderFactory.newInstance()
			.newDocumentBuilder().newDocument();
						
		Element propertiesElement = d.createElementNS(NameSpaces.MetaData,"properties");		
		d.appendChild(propertiesElement);
		Element tableElement = d.createElementNS(NameSpaces.DataServices,"TableName");		
		tableElement.appendChild(d.createTextNode("mytable"));
		
		propertiesElement.appendChild(tableElement);
		
		DomRepresentation domRepresentation = 
			new DomRepresentation(MediaType.APPLICATION_XML,d);	
			
		content.setInlineContent(domRepresentation);
		
		content.setExternalType(MediaType.APPLICATION_XML);
		
		entry.setContent(content);
		
		//atomFeed.getEntries().add(entry);
		
		//atomFeed.setMediaType(MediaType.APPLICATION_ATOM_XML);
		
		entry.write(System.out);
		
	}
	
	private void testCreateRomeSyndFeed(){
		
		// uding thr Rome API
		/*
		SyndFeed feed = new SyndFeedImpl();
		feed.setFeedType("atom_1.0");
		
		feed.setTitle("myFeed");
		
		SyndEntry entry = new SyndEntryImpl();
		
		entry.setTitle("entryTitle");
		
		
		List entries=  new ArrayList();
		entries.add(entry);
		
		feed.setEntries(entries);
		
	
		SyndFeedOutput sfout = new SyndFeedOutput();
		
		sfout.output(feed,new PrintWriter(System.out));
		*/
		
	}
	
	
	private void testCreateDOMATOMFeed() throws ParserConfigurationException, IOException{
		// Let's try to create a DOM representation of the entry.
		
		Document d = DocumentBuilderFactory.newInstance()
		.newDocumentBuilder().newDocument();
		
				
				
		Element propertiesElement = d.createElementNS(NameSpaces.MetaData,"m:properties");		
		d.appendChild(propertiesElement);
		Element tableElement = d.createElementNS(NameSpaces.DataServices,"d:TableName");		
		tableElement.appendChild(d.createTextNode("myTable"));
		
		propertiesElement.appendChild(tableElement);	
		
		
		Namespace metdataNameSpace = Namespace.getNamespace(NameSpaces.MetaData_Prefix,NameSpaces.MetaData);
		
		org.jdom.Element entr = new org.jdom.Element("entry",Namespace.getNamespace("http://www.w3.org/2005/Atom"));
		entr.addNamespaceDeclaration(Namespace.getNamespace(NameSpaces.MetaData_Prefix,NameSpaces.MetaData));
		
		entr.addContent(new org.jdom.Element("properties",metdataNameSpace));
		
		org.jdom.Document jdomdoc = new org.jdom.Document(entr);
		
		XMLOutputter outputter = new XMLOutputter();
		outputter.output(jdomdoc, System.out);
	}

	
	
	
	
	
}

































